<?php
class DB
{
	protected $curLink = null;
	protected static $linkTotal = 0;
	protected static $queryTotal = 0;
	protected static $allLink = array();

    public static function getSlave($app = '')
	{
		static $instance = null;
		if($instance == null)
		{
			$instance = new self();
		}
		$instance->initSlave($app);
		return $instance;
	}

    public static function getMaster($app = '')
	{
		static $instance = null;
		if($instance == null)
		{
			$instance = new self();
		}
		$instance->initMaster($app);
		return $instance;
	}

	public static function getLinkTotal()
	{
	    return self::$linkTotal;
	}

    public static function getQueryTotal()
	{
	    return self::$queryTotal;
	}

	public function query($sql)
	{
		$statement = $this->_query($sql);
		if($statement)
			return $statement->fetchAll(PDO::FETCH_ASSOC);
		return null;
	}

	public function getRow($sql)
	{
		$statement = $this->_query($sql);
		if($statement)
			return $statement->fetch(PDO::FETCH_ASSOC);
		return null;
	}

	public function exec($sql)
	{
	    self::$queryTotal++;
		$return = $this->curLink->exec($sql);
		if($this->errorCode() != '00000')
		{
			if(Config::getConfig('CORE_DEBUG'))
				var_dump($this->errorInfo());
			exit();
		}
		return $return;
	}

	public function lastInsertId()
	{
		return $this->curLink->lastInsertId();
	}

	public function beginTransaction()
	{
		$this->curLink->beginTransaction();
	}
	
	public function rollBack()
	{
		$this->curLink->rollBack();
	}
	
	public function commit()
	{
		$this->curLink->commit();
	}
	
	public function errorInfo()
	{
		return $this->curLink->errorInfo();
	}
	
	public function errorCode()
	{
		return $this->curLink->errorCode();
	}
	
	public function isError()
	{
		return !($this->curLink->errorCode() == '00000');
	}

	private function _query($sql)
	{
	    self::$queryTotal++;
		$statement = $this->curLink->query($sql);
		if($this->errorCode() != '00000')
		{
			if(Config::getConfig('CORE_DEBUG'))
				var_dump($this->errorInfo());
			exit();
		}
		return $statement;
	}

    private function initMaster($app = '')
	{
		$app = empty($app) ? APP_NAME : $app;
		$dbConfig = Config::getConfig('DB_MASTER_CNF', $app);
		if(!isset($dbConfig['dbname']) || empty($dbConfig['dbname']))
		{
		    $dbConfig['dbname'] = Config::getConfig('DB_DBNAME', $app);
		}
	    if(!isset($dbConfig['dbname']) || empty($dbConfig['dbname']))
		{
		    $dbConfig['dbname'] = Config::getConfig('DB_DBNAME', $app);
		}
		if(!isset($dbConfig['charset']) || empty($dbConfig['charset']))
		{
		    $dbConfig['charset'] = Config::getConfig('DB_CHARSET', $app);
		}
		$this->curLink = self::_getDbConn($dbConfig);
	}

	private function initSlave($app = '')
	{
		$app = empty($app) ? APP_NAME : $app;
		$dbSlavesConfig = Config::getConfig('DB_SLAVES', $app);
		$slaveNum = count($dbSlavesConfig);
		$id = 0;
		$dbConfig = array();
		if($slaveNum > 1)
		{
			$id = rand(0, $slaveNum - 1);
    		$dbConfig = $dbSlavesConfig[$id];
		}
		else 
		{
		    $dbConfig = Config::getConfig('DB_MASTER_CNF', $app);
		}
	    if(!isset($dbConfig['dbname']) || empty($dbConfig['dbname']))
		{
		    $dbConfig['dbname'] = Config::getConfig('DB_DBNAME', $app);
		}
	    if(!isset($dbConfig['dbname']) || empty($dbConfig['dbname']))
		{
		    $dbConfig['dbname'] = Config::getConfig('DB_DBNAME', $app);
		}
		if(!isset($dbConfig['charset']) || empty($dbConfig['charset']))
		{
		    $dbConfig['charset'] = Config::getConfig('DB_CHARSET', $app);
		}
		$this->curLink = self::_getDbConn($dbConfig);
	}

	private static function _getDbConn($config)
	{
	    if(empty($config))exit('$config is Null!');
	    $linkKey = self::getLinkKey($config);
	    if(isset(self::$allLink[$linkKey])) return self::$allLink[$linkKey];
	    
	    $dsn = self::getdsn($config);
	    self::$linkTotal++;
	    $charset = $config['charset'] ? $config['charset'] : 'utf8';
		self::$allLink[$linkKey] = new PDO($dsn, 
				$config['user'], 
				$config['pwd'],
				array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \''.$config['charset'].'\''));
		return self::$allLink[$linkKey];
	}

	private static function getdsn($config)
	{
	    return 'mysql:host='.$config['host'].';dbname='.$config['dbname'].';port='.$config['port'];
	}

	private static function getLinkKey($config)
	{
	    $dsn = self::getdsn($config);
	    return md5($dsn.$config['user'].$config['pwd'].$config['charset']);
	}
}